/**
 * Created by oneminute on 2014/5/12.
 */

var arango = require("arango");
var lz = require("../utils/modules")();
var moment = require("moment");

/**
 *
 * @returns {*}
 */
exports.getConnection = function () {
    var db = arango.Connection({
        _name: lz.Config.db.arango.database,
        _server: {
            hostname: lz.Config.db.arango.hostname,
            username: lz.Config.db.arango.username,
            password: lz.Config.db.arango.password
        }
    });

    return db;
};

/**
 *
 * @param _user
 * @param _callback
 */
exports.saveUser = function (_user, _callback) {
    logger.debug("arangodb:saveUser: invoke.", _user.id);
    var db = this.getConnection();
    if (db) {
        logger.debug("arangodb:saveUser: Check whether the user is exist.");
        db.document.head(_user._id, function (_err, _ret, _message) {
            logger.debug("arangodb:saveUser: document.head: status code is ", _message.status);
            if (_message.status == 200) {
                logger.debug("arangodb:saveUser: callback document:head: User %s is exist.", _user.id);
                var options = {};
                options.waitForSync = false;
                db.document.put(_user._id, _user, options, function (_err, _ret, _message) {
                    logger.debug("arangodb:saveUser: callback document:put: ", _message.status);
                    _user.copyFrom(_ret);
                    _callback(_err, _user);
                });
            } else {
                logger.debug("arangodb:saveUser: callback document:head: User %s is not exist.", _user.id);
                var options = {};
                options.waitForSync = false;
                delete _user._id;
                delete _user._key;
                delete _user._rev;
                db.document.create(config.db.arango.users, _user, options, function (_err, _ret, _message) {
                    _user.copyFrom(_ret);
                    logger.debug("arangodb:saveUser: callback document:create: ", _message.status);
                    _callback(_err, _user);
                });
            }
        });
    } else {
        _callback({err: "cannot get arango connection."});
    }
};

exports.getUserByKey = function (_key, _callback) {
    logger.debug("arangodb:getUserByKey: invoke: _key=", _key);
    var db = this.getConnection();
    if (db) {
        db.document.get(_key, {}, function (_err, _ret, _message) {
            logger.debug("arangodb:getUserByKey: callback document:get: ", _ret);
            _callback(_err, _ret);
        })
    } else {
        _callback({err: "cannot get arango connection."});
    }
};

exports.getUserByUid = function (_uid, _callback) {
    lz.Logger.debug("arangodb:getUserByUid: invoke.", _uid);
    var db = this.getConnection();

    db.query.string = lz.Config.db.arango.aqls.GET_USER_BY_ID;

    db.query.exec({'@collection': lz.Config.db.arango.users, "uid": _uid}, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:getUserByUid: ", _ret);
            _callback({err: _ret});
            return;
        }
        lz.Logger.debug("arangodb:getUserByUid: exec callback: ", _ret.result.length);
        if (_ret.result.length > 0) {
            var user = lz.User.create(_ret.result[0]);
            _callback(null, user);
        } else {
            _callback(null, null);
        }
    });
};

exports.getUserByName = function (_uname, _callback) {
    lz.Logger.debug("arangodb:getUserByName: invoke.", _uname);
    var db = this.getConnection();
    db.query.string = lz.Config.db.arango.aqls.GET_USER_BY_NAME;
    db.query.exec({'@collection': lz.Config.db.arango.users, "uname": _uname}, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:getUserByName: ", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR, _err));
            return;
        }
        lz.Logger.debug("arangodb:getUserByName: exec callback: ", _ret.result.length);
        if (_ret.result.length > 0) {
            var user = lz.User.create(_ret.result[0]);
            _callback(null, user);
        } else {
            _callback(null, null);
        }
    });
};

exports.removeObject = function (_key, _callback) {
    logger.debug("arangodb:removeObject: invoke.", _key);
    var db = this.getConnection();
    db.document.delete(_key, null, function (_err, _ret, _message) {
        if (_err) {
            logger.error("arangodb:removeObject: error.", _ret);
            _callback({err: "object is not existed."});
            return;
        }

        _callback(null);
    });
}

exports.saveGoods = function (_goods, _callback) {
    logger.debug("arangodb:saveGoods: invoke.");
    var db = this.getConnection();
    if (db) {
        logger.debug("arangodb:saveGoods: Check whether the saveGoods is exist.");
        db.document.head(_goods._id, function (_err, _ret, _message) {
            if (_message.status == 404) {

            } else if (_message.status == 200) {
                logger.debug("arangodb:saveGoods: callback document:head: Goods %s is exist.", _goods.id);
                var options = {};
                options.waitForSync = false;
                db.document.put(_goods._id, _goods, options, function (_err, _ret, _message) {
                    logger.debug("arangodb:saveGoods: callback document:put: ", _err);
                    _goods._id = _ret._id;
                    _callback(_err, _goods);
                });
            } else {
                logger.debug("arangodb:saveGoods: callback document:head: Goods %s is not exist.", _goods.id);
                var options = {};
                options.waitForSync = false;
                db.document.create(config.db.arango.goods, _goods, options, function (_err, _ret, _message) {
                    logger.debug("arangodb:saveGoods: callback document:create: ", _err);
                    _goods._id = _ret._id;
                    _callback(_err, _goods);
                });
            }
        });
    } else {
        _callback({err: "cannot get arango connection."});
    }
};

exports.getGoodsByKey = function (_key, _callback) {
    logger.debug("arangodb:getGoodsByKey: invoke: _key=", _key);
    var db = this.getConnection();
    if (db) {
        db.document.get(_key, {}, function (_err, _ret, _message) {
            logger.debug("arangodb:getGoodsByKey: callback document:get: ", _ret);
            _callback(_err, _ret);
        })
    } else {
        _callback({err: "cannot get arango connection."});
    }
};

exports.searchByGeo = function (_loc, _radius, _limit, _start, _count, _type, _callback) {
    lz.Logger.debug("arangodb:searchByGeo: invoke. start: %d, end: %d", _start, _count);
    var db = this.getConnection();

    db.query.string = lz.Config.db.arango.aqls.GET_USERS_BY_GEO;
    var params = {
        "@users": lz.Config.db.arango.users,
        "lat": _loc.lat,
        "lon": _loc.lon,
        "radius": _radius,
        "prop": _type,
        "start": _start,
        "count": _count,
        "@collection": lz.Config.db.arango[_type],
        "items": _type
    };
    db.query.exec(params, function (_err, _ret, _message) {
        if (_err) {
            lz.Logger.error("arangodb:searchByGeo: error: ", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        var users = _ret.result;
        if (users.length == 0) {
            _callback(null, []);
            return;
        }
        var items = [];
        users.forEach(function (_user) {
            var userItems = _user.items;
            userItems.forEach(function (_item) {
                delete _item._id;
                delete _item._key;
                delete _item._rev;
                delete _item.onsale;
                delete _item.class;
                //delete _item.publishDate;

                _item.distance = parseInt(_user.distance);
                _item.name = _user.name;
                _item.price = parseFloat(_item.price).toFixed(2);
                _item.photo = _user.photo || "";

                items.push(_item);
            });
        });
        items.sort(function (_a, _b) {
            //return _b.publishDate.localeCompare(_a);
            var d = _a.distance - _b.distance;
            //lz.Logger.debug(d);
            if (d != 0) {
                return d;
            } else {
                //return _b.publishDate.localeCompare(_a);
                var ta = moment(_a.publishDate, lz.Config.datetimeFormat);
                var tb = moment(_b.publishDate, lz.Config.datetimeFormat);
                if (ta.isAfter(tb)) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
        _callback(null, items);
    });
};

exports.saveObject = function (_obj, _collection, _callback) {
    lz.Logger.debug("arangodb:saveObject: invoke.");
    var db = this.getConnection();
    if (db) {
        lz.Logger.debug("arangodb:saveObject: 检查所要保存的对象是否存在.");
        db.document.head(_obj._id, function (_err, _ret, _message) {
            lz.Logger.debug("arangodb:saveObject: 查寻对象是否已存在结果: status: %d.", _message.status, _err);
            switch (_message.status) {
                case 400:
                case 404:
                case 412:
                {
                    // 对象不存在
                    var options = {};
                    options.waitForSync = false;
                    //delete _obj._id;
                    //delete _obj._key;
                    //delete _obj._rev;
                    db.document.create(_collection, _obj, options, function (_err, _ret, _message) {
                        if (_err) {
                            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR, _message));
                            return;
                        }
                        _obj._id = _ret._id;
                        _obj._key = _ret._key;
                        _obj._rev = _ret._rev;
                        lz.Logger.debug("arangodb:saveObject: 创建对象后返回: ");
                        _callback(null, _obj);
                    });
                    break;
                }
                case 304:
                case 200:
                {
                    // 对象已存在
                    var options = {};
                    options.waitForSync = false;
                    db.document.put(_obj._id, _obj, options, function (_err, _ret, _message) {
                        if (_err) {
                            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR, _message));
                            return;
                        }
                        lz.Logger.debug("arangodb:saveObject: callback document:put: ", _message.status);
                        lz.Utils.copyObj(_ret, _obj);
                        _callback(null, _obj);
                    });
                    break;
                }
            }
        });
    }
};

exports.getObjectById = function (_id, _callback) {
    lz.Logger.debug("arangodb:getObjectById: invoke: _id=", _id);
    var db = this.getConnection();
    if (db) {
        db.document.get(_id, {}, function (_err, _ret, _message) {
            lz.Logger.debug("arangodb:getObjectById: callback document:get: ");
            if (_err) {
                switch (_message.status) {
                    case 400:
                    case 404:
                    case 412:
                        _callback(null, null);
                        break;
                    default:
                        _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
                }
            } else {
                _callback(null, _ret);
            }
        })
    } else {
        _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));

    }
};

exports.deleteObjectById = function (_id, _callback) {
    lz.Logger.debug("arangodb:deleteObjectById: invoke: _id=", _id);
    var db = this.getConnection();
    if (db) {
        db.document.delete(_id, null, function (_err, _ret, _message) {
            if (_err) {
                lz.Logger.error("arangodb:deleteObjectById: error.", _ret);
                _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
                return;
            }

            _callback(null);
        });
    }
};

exports.getObjectByObjectId = function (_oid, _collection, _callback) {
    lz.Logger.debug("arangodb:getObjectByObjectId: invoke.", _oid);
    var db = this.getConnection();

    db.query.string = lz.Config.db.arango.aqls.GET_OBJECT_BY_ID;

    db.query.exec({'@collection': _collection, "oid": _oid}, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:getObjectByObjectId: ", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        lz.Logger.debug("arangodb:getObjectByObjectId: exec callback: ", _ret.result.length);
        if (_ret.result.length > 0) {
            _callback(null, _ret.result[0]);
        } else {
            _callback(null, null);
        }
    });
};

exports.getObjectByAQL = function (_aql, _params, _callback) {
    lz.Logger.debug("arangodb:getObjectByAQL: 调用.", _aql);
    var db = this.getConnection();

    db.query.string = _aql;

    db.query.exec(_params, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:getObjectByAQL: 执行失败。", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        lz.Logger.debug("arangodb:getObjectByAQL: 执行完毕: ", _ret.result.length);
        if (_ret.result.length > 0) {
            _callback(null, _ret.result[0]);
        } else {
            _callback(null, null);
        }
    });
};

exports.listObjectsByAQL = function (_aql, _params, _callback) {
    lz.Logger.debug("arangodb:listObjectsByAQL: 调用.", _aql);
    var db = this.getConnection();

    db.query.string = _aql;

    db.query.exec(_params, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:listObjectsByAQL: ", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        lz.Logger.debug("arangodb:listObjectByAQL:: 执行完毕: ", _ret.result.length);
        if (_ret.result.length > 0) {
            _callback(null, _ret.result);
        } else {
            _callback(null, []);
        }
    });
};

exports.countObjectsByAQL = function (_aql, _params, _callback) {
    lz.Logger.debug("arangodb:countObjectsByAQL: 调用.", _aql, _params);
    var db = this.getConnection();

    db.query.string = _aql;

    db.query.exec(_params, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:listObjectsByAQL: ", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        lz.Logger.debug("arangodb:listObjectByAQL:: 执行完毕: ", _ret.result.length);
        _callback(null, _ret.result.length);
    });
};

exports.updateObjectProperties = function (_properties, _collection, _condition, _callback) {
    lz.Logger.debug("arangodb:updateObjectProperties: 调用。", _properties);
    var db = this.getConnection();
    db.query.string = lz.Config.db.arango.aqls.MODITY_OBJECT_PROPERTY;
    var params = {
        "@collection": _collection,
        "fprop": _condition.prop,
        "fvalue": _condition.value,
        "properties": _properties
    };
    db.query.exec(params, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:updateObjectProperties: 失败。", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        lz.Logger.debug("arangodb:updateObjectProperties: 成功。", _ret);
        _callback(null);
    });
};

exports.setAllUsersOffline = function (_callback) {
    lz.Logger.debug("arangodb:setAllUsersOffline: 调用。");
    var db = this.getConnection();
    db.query.string = lz.Config.db.arango.aqls.SET_ALL_USERS_OFFLINE;
    db.query.exec({"@collection": lz.Config.db.arango.users}, function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:setAllUsersOffline: 失败。", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }
        _callback(null);
    });
};

/**
 * 获取系统当前的统计信息。
 *
 * @param _callback
 */
exports.getSystemSummary = function (_callback) {
    lz.Logger.debug("arangodb:getSystemSummary: 调用。");
    var db = this.getConnection();
    db.query.string = lz.Config.db.arango.aqls.GET_SUMMARY;
    db.query.exec(function (_err, _ret) {
        if (_err) {
            lz.Logger.error("arangodb:getSystemSummary: 失败。", _ret);
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR));
            return;
        }

        _callback(null, _ret.result);
    });
};

/**
 * 保存用户的操作记录。
 *
 * @param _record
 * @param _callback
 */
exports.saveUserRecord = function (_record, _callback) {
    lz.Logger.debug("arangodb:saveUserRecord: 调用。");
    var db = this.getConnection();
    // 对象不存在
    var options = {};
    options.waitForSync = false;
    db.document.create(lz.Config.db.arango.records, _record, options, function (_err, _ret) {
        if (_err) {
            _callback(lz.Config.errors.getError(lz.Config.errors.ARANGODB_SYSTEM_ERROR, _ret));
            return;
        }
        _obj._id = _ret._id;
        _obj._key = _ret._key;
        _obj._rev = _ret._rev;
        lz.Logger.debug("arangodb:saveUserRecord: 创建对象后返回: ");
        _callback(null, _obj);
    });
};
